﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data.Linq;
using System.Linq;

namespace InvoiceInvoker.Logic.Repositories
{
	public class InvoiceRepository : InvoiceInvoker.Logic.RepositoryInterfaces.IInvoiceRepository
	{
		private string _connectionString;
		private int _registeredSellerId;
		private DataLoadOptions _loadOptions;

		public InvoiceRepository(int registeredSellerId)
		{
			_connectionString = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;

			this._registeredSellerId = registeredSellerId;

			_loadOptions = new DataLoadOptions();
			_loadOptions.LoadWith<Invoice>(x => x.Customer);
			_loadOptions.LoadWith<Invoice>(x => x.Products);
			_loadOptions.LoadWith<Invoice>(x => x.Seller);
		}

		public List<Invoice> GetAll()
		{
			using (MainDataContext dataContext = new MainDataContext(_connectionString))
			{
				dataContext.LoadOptions = _loadOptions;
				var query = from invoice in dataContext.Invoices
							where invoice.RegisteredSellerId == _registeredSellerId
							orderby invoice.CreationDate descending, invoice.Number descending
							select invoice;
				return query.ToList();
			}
		}

		public List<Invoice> GetByStatus(Invoice.InvoiceStatus status)
		{
			using (MainDataContext dataContext = new MainDataContext(_connectionString))
			{
				dataContext.LoadOptions = _loadOptions;
				var query = from invoice in dataContext.Invoices
							where invoice.RegisteredSellerId == _registeredSellerId &&
								  invoice.Status == status.ToString()
							orderby invoice.CreationDate descending, invoice.Number descending
							select invoice;
				return query.ToList();
			}
		}

		public List<Invoice> GetByDate(DateTime dateFrom, DateTime dateTo)
		{
			using (MainDataContext dataContext = new MainDataContext(_connectionString))
			{
				dataContext.LoadOptions = _loadOptions;
				var query = from invoice in dataContext.Invoices
							where invoice.RegisteredSellerId == _registeredSellerId &&
								  invoice.CreationDate.Value >= dateFrom && invoice.CreationDate <= dateTo
							orderby invoice.CreationDate descending, invoice.Number descending
							select invoice;
				return query.ToList();
			}
		}

		public List<Invoice> GetByCustomer(string companyName)
		{
			using (MainDataContext dataContext = new MainDataContext(_connectionString))
			{
				dataContext.LoadOptions = _loadOptions;
				var query = from invoice in dataContext.Invoices
							where invoice.RegisteredSellerId == _registeredSellerId &&
								  invoice.Customer.CompanyName.StartsWith(companyName)
							orderby invoice.CreationDate descending, invoice.Number descending
							select invoice;
				return query.ToList();
			}
		}

		public List<Invoice> GetByProduct(string productName)
		{
			using (MainDataContext dataContext = new MainDataContext(_connectionString))
			{
				dataContext.LoadOptions = _loadOptions;
				var query = from invoice in dataContext.Invoices
							where invoice.RegisteredSellerId == _registeredSellerId &&
								  invoice.Products.Any(x => x.Name.StartsWith(productName))
							orderby invoice.CreationDate descending, invoice.Number descending
							select invoice;
				return query.ToList();
			}
		}

		public List<Invoice> GetByValue(decimal valueFrom, decimal valueTo)
		{
			using (MainDataContext dataContext = new MainDataContext(_connectionString))
			{
				dataContext.LoadOptions = _loadOptions;
				var query = from invoice in dataContext.Invoices
							where invoice.RegisteredSellerId == _registeredSellerId &&
								  invoice.ToPay.Value >= valueFrom && invoice.ToPay.Value <= valueTo
							orderby invoice.CreationDate descending, invoice.Number descending
							select invoice;
				return query.ToList();
			}
		}

		public List<Invoice> GetByExpression(Func<Invoice, bool> expression)
		{
			using (MainDataContext dataContext = new MainDataContext(_connectionString))
			{
				dataContext.LoadOptions = _loadOptions;
				var mainQuery = from invoice in dataContext.Invoices
								where invoice.RegisteredSellerId == _registeredSellerId
								orderby invoice.CreationDate descending, invoice.Number descending
								select invoice;
				return mainQuery.Where(expression).ToList();
			}
		}

		public Invoice GetById(int id)
		{
			using (MainDataContext dataContext = new MainDataContext(_connectionString))
			{
				dataContext.LoadOptions = _loadOptions;
				return dataContext.Invoices.SingleOrDefault(invoice => invoice.Id == id);
			}
		}

		public void Add(Invoice item)
		{
			using (MainDataContext dataContext = new MainDataContext(_connectionString))
			{
				var query = from seller in dataContext.RegisteredSellers where seller.Id == _registeredSellerId select seller;
				RegisteredSeller registeredSeller = query.SingleOrDefault();

				registeredSeller.UpdateLastInvoiceNumber(item.Number);
				item.Seller = registeredSeller.ToSeller();

				dataContext.Invoices.InsertOnSubmit(item);
				dataContext.SubmitChanges();
			}
		}

		public void Remove(int itemId)
		{
			using (MainDataContext dataContext = new MainDataContext(_connectionString))
			{
				var query = from invoice in dataContext.Invoices where invoice.Id == itemId select invoice;
				Invoice item = query.SingleOrDefault();

				dataContext.Customers.DeleteOnSubmit(item.Customer);
				dataContext.Products.DeleteAllOnSubmit(item.Products);
				dataContext.Invoices.DeleteOnSubmit(item);
				dataContext.SubmitChanges();
			}
		}

		public void Update(Invoice item)
		{
			using (MainDataContext dataContext = new MainDataContext(_connectionString))
			{
				dataContext.Invoices.Attach(item, GetById(item.Id));
				dataContext.SubmitChanges();
			}
		}
	}
}
